package com.dhcc.bpm.modules.system.service.impl;


import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dhcc.bpm.common.cache.SysCache;
import com.dhcc.bpm.common.constant.CommonConstant;
import com.dhcc.bpm.common.exception.BusinessException;
import com.dhcc.bpm.common.utils.AES2Util;
import com.dhcc.bpm.modules.common.vo.SelectVo;
import com.dhcc.bpm.modules.scf.util.OBSUtil;
import com.dhcc.bpm.modules.system.entity.Param;
import com.dhcc.bpm.modules.system.entity.User;
import com.dhcc.bpm.modules.system.entity.UserInfo;
import com.dhcc.bpm.modules.system.entity.UserRole;
import com.dhcc.bpm.modules.system.mapper.UserMapper;
import com.dhcc.bpm.modules.system.service.IParamService;
import com.dhcc.bpm.modules.system.service.IUserRoleService;
import com.dhcc.bpm.modules.system.service.IUserService;
import com.dhcc.bpm.modules.system.vo.UserVO;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.DigestUtil;
import org.springblade.core.tool.utils.Func;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName UserServiceImpl
 * @Description 服务实现类
 * @Author sjm
 * @Date 2020/2/21 0021 15:16
 * @Version V1.0
 * @Copyright: 2020 东华软件 . All rights reserved.
 **/
@Service
@AllArgsConstructor
public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implements IUserService {
    private final static Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
    private IUserRoleService userRoleService;

    private StringRedisTemplate stringRedisTemplate;
    private final OBSUtil obsUtil;

    //用户原密碼錯誤次数计数  redisKey 前缀
    private final static String PASSWORD_ERRORS_COUNT = "password_errors_count_";

    //用户密碼錯誤次數過多是否被锁定  redisKey 前缀
    private final static String PASSWORD_ERRORS_IS_LOCK = "password_errors_is_lock_";

    //用户登录次数计数  redisKey 前缀
    private final static String SHIRO_LOGIN_COUNT = "shiro_login_count_";

    //用户登录是否被锁定  redisKey 前缀
    private final static String SHIRO_IS_LOCK = "shiro_is_lock_";

    IParamService paramService;
    /**
     * 新增用户
     *
     * @param user
     * @return boolean
     * @Author sjm
     * @Date 19:22 2020/2/21 0021
     **/
    @Override
    public boolean submit(User user) {
//        if (Func.isNotEmpty(user.getPassword())) {
//            user.setPassword(DigestUtil.encrypt(user.getPassword()));
//        }
        // 解密密码
        try {
            Param param = paramService.getParamByKey(CommonConstant.PASS_SECRET);
            String decryptKey =  param == null ? CommonConstant.INIT_SECRET : param.getParamValue();

            user.setPassword(AES2Util.decrypt(user.getPassword(), decryptKey));
        } catch (Exception e) {
            log.error("解密密码异常{}", e);
        }
        Integer cnt = Math.toIntExact(baseMapper.selectCount(Wrappers.<User>query().lambda().eq(User::getTenantId, Func.toStr(user.getTenantId(), BladeConstant.ADMIN_TENANT_ID)).eq(User::getAccount, user.getAccount())));
        if (cnt > 0 && Func.isEmpty(user.getId())) {
            throw new BusinessException("当前用户已存在!");
        }
        return save(user);
    }

    /**
     * 修改用户
     *
     * @param user
     * @return boolean
     * @Author sjm
     * @Date 19:22 2020/2/21 0021
     **/
    @Override
    public boolean updateUser(User user) {
        user.setPassword(null);
        return updateById(user);
    }
    /**
     * @Description 查询用户邮箱
     * @Author daina
     * @Date 11:18 2020/3/28
     * @param user
     * @return java.util.List<com.dhcc.bpm.modules.system.entity.User>
     **/
    @Override
    public User selectByEmail(User user){
        return baseMapper.selectByEmail(user);
    }

    /**
     * @Description 查询用户手机
     * @Author daina
     * @Date 11:45 2020/3/28
     * @param user
     * @return java.util.List<com.dhcc.bpm.modules.system.entity.User>
     **/
    @Override
    public User selectByPhone(User user){
        return baseMapper.selectByPhone(user);
    }
    /**
     * 自定义分页
     *
     * @param page
     * @param user
     * @return com.baomidou.mybatisplus.core.metadata.IPage<com.dhcc.bpm.modules.system.entity.User>
     * @Author sjm
     * @Date 19:22 2020/2/21 0021
     **/
    @Override
    public IPage<User> selectUserPage(IPage<User> page, User user) {
        return page.setRecords(baseMapper.selectUserPage(page, user));
    }

    /**
     * @param page
     * @param user
     * @return com.baomidou.mybatisplus.core.metadata.IPage<com.dhcc.bpm.modules.system.vo.UserVO>
     * @Description 查询板块设置的管理员
     * @Author daina
     * @Date 10:31 2020/3/5
     **/
    @Override
    public IPage<UserVO> listTopicUser(IPage<UserVO> page, UserVO user) {
        return page.setRecords(baseMapper.listTopicUser(page, user));
    }

    /**
     * 用户信息
     *
     * @param userId
     * @return com.dhcc.bpm.modules.system.entity.UserInfo
     * @Author sjm
     * @Date 19:23 2020/2/21 0021
     **/
    @Override
    public UserInfo userInfo(Long userId) {
        UserInfo userInfo = new UserInfo();
        User user = baseMapper.selectById(userId);
        userInfo.setUser(user);
        if (Func.isNotEmpty(user)) {
            List<String> roleAlias = SysCache.getRoleAliases(user.getRoleId());
            userInfo.setRoles(roleAlias);
        }
        return userInfo;
    }

    /**
     * 用户信息
     *
     * @param tenantId
     * @param account
     * @param password
     * @return com.dhcc.bpm.modules.system.entity.UserInfo
     * @Author sjm
     * @Date 19:23 2020/2/21 0021
     **/
    @Override
    public UserInfo userInfo(String tenantId, String account, String password) {
        UserInfo userInfo = new UserInfo();
        User user = baseMapper.getUser(tenantId, account, password);
        userInfo.setUser(user);
        if (Func.isNotEmpty(user)) {
            List<String> roleAlias = SysCache.getRoleAliases(user.getRoleId());
            userInfo.setRoles(roleAlias);
        }
        return userInfo;
    }

    /**
     * 给用户设置角色
     *
     * @param userIds
     * @param roleIds
     * @return boolean
     * @Author sjm
     * @Date 19:23 2020/2/21 0021
     **/
    @Override
    public boolean grant(String userIds, String roleIds) {
        Long userId = Long.valueOf(userIds);
        //维护到用户角色中间表
        List<UserRole> list = userRoleService.selectUserByUserId(userId);
        for (UserRole data : list) {
            userRoleService.removeByUserId(data.getUserId());
        }
        userRoleService.batchUserRole(userId, roleIds);
        //维护用户表
        User user = new User();
        user.setRoleId(roleIds);
        return this.update(user, Wrappers.<User>update().lambda().in(User::getId, Func.toLongList(userIds)));
    }

    /**
     * 初始化密码
     *
     * @param userIds
     * @return boolean
     * @Author sjm
     * @Date 19:23 2020/2/21 0021
     **/
    @Override
    public boolean resetPassword(String userIds,String resetPassword) {
        User user = new User();
        // 解密密码
        try {
            Param param = paramService.getParamByKey(CommonConstant.PASS_SECRET);
            String decryptKey =  param == null ? CommonConstant.INIT_SECRET : param.getParamValue();
            resetPassword = AES2Util.decrypt(resetPassword, decryptKey);
        } catch (Exception e) {
            log.error("解密密码异常{}", e);
        }
        user.setPassword(DigestUtil.encrypt(CommonConstant.DEFAULT_PASSWORD));
        if(resetPassword!=null && !"".equals(resetPassword)){
            user.setPassword(resetPassword);
        }else{
            Param param = paramService.getParamByKey(CommonConstant.INTI_PASS);
            user.setPassword(param.getParamValue());
//            user.setPassword("ac44151dd474f7ed99673cae636d45f34f714df3");
        }
        user.setUpdateTime(DateUtil.now());
        boolean bool = this.update(user, Wrappers.<User>update().lambda().in(User::getId, Func.toLongList(userIds)));
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        for(long id :Func.toLongList(userIds)){
            user = getById(id);
            //清空登录计数
            opsForValue.set(SHIRO_LOGIN_COUNT + user.getAccount(), "0");
            //清空锁
            opsForValue.set(SHIRO_IS_LOCK + user.getAccount(), "");
        }
        return bool;
    }

    /**
     * 修改密码
     *
     * @param userId
     * @param oldPassword
     * @param newPassword
     * @param newPassword1
     * @return boolean
     * @Author sjm
     * @Date 19:23 2020/2/21 0021
     **/
    @Override
    public boolean updatePassword(Long userId, String oldPassword, String newPassword, String newPassword1) {
        User user = getById(userId);
        // 解密密码
        try {
            Param param = paramService.getParamByKey(CommonConstant.PASS_SECRET);
            String decryptKey =  param == null ? CommonConstant.INIT_SECRET : param.getParamValue();

            oldPassword = AES2Util.decrypt(oldPassword, decryptKey);
            newPassword = AES2Util.decrypt(newPassword, decryptKey);
            newPassword1 = AES2Util.decrypt(newPassword1, decryptKey);
        } catch (Exception e) {
            log.error("解密密码异常{}", e);
        }
        if(newPassword.equals(user.getPassword())){
            throw new ServiceException("新密码不能与原密码相同!");
        }
        if (!newPassword.equals(newPassword1)) {
            throw new ServiceException("请输入正确的确认密码!");
        }

        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        log.info("用户:{}，修改密码的次数是:{}", userId, opsForValue.get(PASSWORD_ERRORS_COUNT + userId));

        //如果这个账号登陆异常，则在登陆页面提醒。
        if (opsForValue.get(PASSWORD_ERRORS_COUNT + userId) != null) {
            if (Integer.parseInt(opsForValue.get(PASSWORD_ERRORS_COUNT + userId)) >= 3) {
                if ("LOCK".equals(opsForValue.get(PASSWORD_ERRORS_IS_LOCK + userId))) {
                    //计数大于3次，设置用户被锁定一分钟
                    throw new ServiceException("原密码输入错误3次，该帐号10分钟内禁止修改密码！");
                } else {
                    //清空登录计数
                    opsForValue.set(PASSWORD_ERRORS_COUNT + userId, "0");
                }
            }
        }

//		if (!user.getPassword().equals(DigestUtil.encrypt(oldPassword))) {
        if (!user.getPassword().equals(oldPassword)) {
            //访问一次，计数一次
            //每次增加1
            opsForValue.increment(PASSWORD_ERRORS_COUNT + userId, 1);
            log.info("用户:{}，修改密码的次数是:{}", user.getName(), opsForValue.get(PASSWORD_ERRORS_COUNT + userId));
            //实现锁定
            if (Integer.parseInt(opsForValue.get(PASSWORD_ERRORS_COUNT + userId)) >= 3) {
                //锁住这个账号，值是LOCK。
                opsForValue.set(PASSWORD_ERRORS_IS_LOCK + userId, "LOCK");
                //expire  变量存活期限
                stringRedisTemplate.expire(PASSWORD_ERRORS_IS_LOCK + userId, 10, TimeUnit.MINUTES);
                throw new ServiceException("原密码输入错误3次，该帐号10分钟内禁止修改密码！");
            } else {
                throw new ServiceException("原密码不正确!");
            }
        }

        //清空登录计数
        opsForValue.set(PASSWORD_ERRORS_COUNT + userId, "0");
        //清空锁
        opsForValue.set(PASSWORD_ERRORS_IS_LOCK + userId, "");
//        return this.update(Wrappers.<User>update().lambda().set(User::getPassword, DigestUtil.encrypt(newPassword)).eq(User::getId, userId));
		return this.update(Wrappers.<User>update().lambda().set(User::getPassword, newPassword).set(User::getUpdateTime, new Date()).eq(User::getId, userId));
    }

    /**
     * 删除用户
     *
     * @param userIds
     * @return boolean
     * @Author sjm
     * @Date 19:23 2020/2/21 0021
     **/
    @Override
    public boolean removeUser(String userIds) {
        if (Func.contains(Func.toLongArray(userIds), SecureUtil.getUserId())) {
            throw new BusinessException("不能删除本账号!");
        }
        return deleteLogic(Func.toLongList(userIds));
//        return baseMapper.removeByIds(userIds.split(","));
    }

    /**
     * 根据账号查询用户信息
     *
     * @param account
     * @return com.dhcc.bpm.modules.system.entity.User
     * @Author sjm
     * @Date 19:24 2020/2/21 0021
     **/
    @Override
    public User selectUserByaccount(String account) {
        return baseMapper.selectUserByaccount(account);
    }

    /**
     * @Description TODO
     * @Author xiafayu
     * @Date 2020/3/20 15:22
     * @param
     * @return java.util.List<com.dhcc.bpm.modules.common.vo.SelectVo>
     * @throws 
     **/
    @Override
    public List<SelectVo> selectUserName() {
        return baseMapper.selectUserName();
    }

    @Override
    public List<String> selectUserNameByIds(List<Long> ids) {
        return baseMapper.selectUserNameByIds(ids);
    }
    @Override
    public List<User> getByRoleId(String roleId) {
        return baseMapper.getByRoleId(roleId);
    }

    @Override
    public User getById(Long id) {
        User user = baseMapper.getById(id);
        String avatarOld = user.getAvatar();
        String downloadUrl = obsUtil.getDownloadUrl(avatarOld);
        user.setAvatar(downloadUrl);
        return user;
    }

}
